package com.ruiyian.netty.nettyclient;

import com.ruiyian.common.utils.encoder.Decoder;
import com.ruiyian.common.utils.encoder.Encoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * netty客户端启停类
 */
@Slf4j
@Data
@Component
public class NettyStarter {
   private static  Map<String, ChannelFuture> connectMap = new HashMap<>();

    public static Map<String, ChannelFuture> getConnectMap() {
        return connectMap;
    }

    public static void setConnectRemove(String ip, Integer port) {
        connectMap.remove(ip+":"+port);
    }

    public static void setConnect(String ip, Integer port,ChannelFuture cf) {
        connectMap.put(ip+":"+port,cf);
    }

    private static Channel channel;
    private static boolean isStart = false;
    static Bootstrap bootstrap = new Bootstrap();
    private static EventLoopGroup workGroup = new NioEventLoopGroup();
    public static int pointValue;
    public static String planName;
    private static Channel serviceChannel;

    public static Channel getServiceChannel() {
        return serviceChannel;
    }

    public static void setServiceChannel(Channel serviceChannel) {
        NettyStarter.serviceChannel = serviceChannel;
    }

    public static void clientStart(String ip,Integer port) {
        /*if (isStart) {
            return;
        }*/
        workGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(workGroup);
        bootstrap.option(NioChannelOption.SO_REUSEADDR, true)
                .option(NioChannelOption.TCP_NODELAY, true)
                .option(NioChannelOption.SO_KEEPALIVE, true);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                //TODO 处理分包粘包
                socketChannel.pipeline().addLast(new IdleStateHandler(30, 30, 30));
//                socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024*6));
                socketChannel.pipeline().addLast("decoder", new Decoder());
                socketChannel.pipeline().addLast("encoder", new Encoder());
                socketChannel.pipeline().addLast("clientHandler",new ClientHandler());
            }

        });
//        ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
        bootstrap.remoteAddress(new InetSocketAddress(ip,port));
        doConnect(ip,port);
    }

    /**
     * 连接服务器
     */
    public static void doConnect(String ip,Integer port) {
        ChannelFuture cf = bootstrap.connect(ip,port).addListener((ChannelFuture f) -> {
            if (!f.isSuccess()) {
                f.channel().closeFuture();
                f.channel().remoteAddress();
                log.info(ip+"连接服务端失败，5s后重连...");
                connectMap.remove(ip+":"+port);
                final EventLoop loop = f.channel().eventLoop();
                // 重连的循环
                loop.schedule(new Runnable() {
                    @Override
                    public void run() {
                        doConnect(ip,port);
                    }
                }, 5L, TimeUnit.SECONDS);
            } else {
//                connectMap.put(ip+":"+port,f);
//                System.out.println(ip+"建立连接，连接服务端成功！");
                //log.info("建立连接，连接服务端成功！");
                isStart = true;
                log.info("启动客户端ip->"+f.channel().localAddress());
            }
        });

//        connectMap.put(ip+":"+port,cf);
        channel = cf.channel();

    }

    /**
     * 停止连接
     * @return
     */
    public synchronized  boolean clientStop() {
        try {
            /*if (!isStart) return false;*/
            System.out.println("关闭连接！");
            //log.info("关闭连接！");
            workGroup.shutdownGracefully().sync();
            isStart = false;
        } catch (Exception e) {
            log.error("关闭异常");
        }
        return true;
    }

    /**
     * 客户端发送消息,先握手,在读写
     * @param msg
     * @param
     */
    public static void sendMessage(String msg,Channel serChannel) {
        serviceChannel = serChannel;
        try {
            channel.writeAndFlush(msg+"\n").sync();
        } catch (InterruptedException e) {
            log.error("发送消息异常");
        }
    }

}
